﻿package com.snakedickgames.common.rendering2D 
{
    import com.pblabs.engine.PBUtil;
    import com.pblabs.rendering2D.DisplayObjectRenderer;
    import com.pblabs.rendering2D.DisplayObjectScene;
    import com.pblabs.rendering2D.SceneAlignment;
    import flash.geom.Point;
    import flash.geom.Rectangle;
    import com.pblabs.rendering2D.DisplayObjectSceneLayer;
    import com.pblabs.engine.debug.Logger;
    
    /**
     *  Attempts to keep multiple tracked objects on the screen
     *  Differs from the basic DisplayObjectScene in that trackObject is now trackObjects, an array.
        xml example:
        <component type="...DisplayObjectSceneMultiTrack" name="Scene">
            <trackObjects>
                <_ entityName="SomeEntity"/>
                <_ entityName="AnotherEntity"/>
                <_ entityName="YetAnotherEntity"/>
            </trackObjects>
            ...other config options...
        </component>
     *
     */
    public class DisplayObjectSceneMultiTrack extends DisplayObjectScene
    {
        public var trackObjects:Array;
        public var trackBoundsMarginRatio:Number = 1;
        
        public function get trackObjectsCentroid():Point
        {
            if(trackObjects)
            {
                var numObjects:int = 0;
                var accPos:Point = new Point();
                for (var i:* in trackObjects)
                {
                    var obj:DisplayObjectRenderer = trackObjects[i];
                    if (obj)
                    {
                        accPos = accPos.add(obj.position);
                        numObjects++;
                    }
                }
                
                // why do they invert this?
                accPos = new Point(-(accPos.x / numObjects),
                                    -(accPos.y / numObjects));            
                return accPos;
            }
            return null;
        }
        
        public function get trackObjectsBounds():Rectangle
        {
            var rect:Rectangle;
            if(trackObjects)
            {                
                for (var i:* in trackObjects)
                {
                    var obj:DisplayObjectRenderer = trackObjects[i];
                    if (obj)
                    {
                        var objPos:Point = obj.position;
                        // do we need to expand the rectangle to fit this point?
                        if (!rect)
                        {
                            rect = new Rectangle(objPos.x, objPos.y, 0, 0);
                            continue;
                        }
                        if (rect.containsPoint(objPos))
                            continue;
                        
                        // expand the rect
                        if (rect.left > objPos.x)
                            rect.left = objPos.x;
                        if (rect.right < objPos.x)
                            rect.right = objPos.x;
                        if (rect.top > objPos.y)
                            rect.top = objPos.y;
                        if (rect.bottom < objPos.y)
                            rect.bottom = objPos.y;
                    }
                }
            }
            return rect;
        }
        
        override public function get sceneViewBounds():Rectangle
        {
            if(!sceneView)
                return null;
                
            // Make sure we are up to date with latest track.
            if(trackObjects)
            {
                position = trackObjectsCentroid;
                // set zoom level
                var objBounds:Rectangle = trackObjectsBounds;
                if (objBounds)
                {
                    objBounds.width += sceneView.width * trackBoundsMarginRatio;
                    objBounds.height += sceneView.height * trackBoundsMarginRatio;
                    var ratioX:Number = objBounds.width / sceneView.width;
                    var ratioY:Number = objBounds.height / sceneView.height;
                    var extremeZoom:Number = ratioX > ratioY ? ratioX : ratioY;
                    if (extremeZoom != 0)
                    {
                        zoom = 1/extremeZoom;
                    }
                }
            }
            
            if(trackLimitRectangle != null)
            {
                var centeredLimitBounds:Rectangle = new Rectangle( trackLimitRectangle.x     + (sceneView.width * 0.5) / zoom, trackLimitRectangle.y      + (sceneView.height * 0.5) / zoom,
                                                                   trackLimitRectangle.width - (sceneView.width / zoom)      , trackLimitRectangle.height - (sceneView.height/zoom) );
                
                                
                position = new Point(PBUtil.clamp(position.x, -centeredLimitBounds.right, -centeredLimitBounds.left ), 
                                     PBUtil.clamp(position.y, -centeredLimitBounds.bottom, -centeredLimitBounds.top) );
            }

            updateTransform();

            // What region of the scene are we currently viewing?
            SceneAlignment.calculate(_tempPoint, sceneAlignment, sceneView.width / zoom, sceneView.height / zoom);
            
            _sceneViewBoundsCache.x = -position.x - _tempPoint.x; 
            _sceneViewBoundsCache.y = -position.y - _tempPoint.y;
            _sceneViewBoundsCache.width = sceneView.width / zoom;
            _sceneViewBoundsCache.height = sceneView.height / zoom;
            
            return _sceneViewBoundsCache;
        }
        
        public override function onFrame(elapsed:Number) : void
        {
            if(!sceneView)
            {
                Logger.warn(this, "updateTransform", "sceneView is null, so we aren't rendering."); 
                return;
            }
            /*
            // Make sure we are up to date with latest track.
            if(trackObjects)
            {
                position = trackObjectsCentroid;
                // set zoom level
                var objBounds:Rectangle = trackObjectsBounds;
                if (objBounds)
                {
                    objBounds.width += sceneView.width * trackBoundsMarginRatio;
                    objBounds.height += sceneView.height * trackBoundsMarginRatio;
                    var ratioX:Number = objBounds.width / sceneView.width;
                    var ratioY:Number = objBounds.height / sceneView.height;
                    var extremeZoom:Number = ratioX > ratioY ? ratioX : ratioY;
                    if (extremeZoom != 0)
                    {
                        zoom = 1/extremeZoom;
                    }
                }
            }
      
            // Apply limit to camera movement.
            if(trackLimitRectangle != null)
            {
                var centeredLimitBounds:Rectangle = new Rectangle( trackLimitRectangle.x     + sceneView.width * 0.5, trackLimitRectangle.y      + sceneView.height * 0.5,
                                                                   trackLimitRectangle.width - sceneView.width      , trackLimitRectangle.height - sceneView.height );
                
                position = new Point(PBUtil.clamp(position.x, -centeredLimitBounds.right, -centeredLimitBounds.left ), 
                                     PBUtil.clamp(position.y, -centeredLimitBounds.bottom, -centeredLimitBounds.top) );
            }

            // Make sure transforms are up to date.
            updateTransform();

            // This is disabled, because it causes everything in the screen
            // to invalidate and redraw.
            */
            sceneViewBounds;
            //PBE.pushStageQuality(StageQuality.LOW);
            
            // Give layers a chance to sort and update.
            for each(var l:DisplayObjectSceneLayer in _layers)
                l.onRender();

            //PBE.pushStageQuality(StageQuality.HIGH);
        }
    }

}